{"componentChunkName":"component---src-templates-article-js","path":"/article/how-to-cope-with-frontend-backend-communication-using-rest-api","result":{"data":{"strapiArticles":{"title":"How to cope with frontend-backend communication using React, Express and REST API? ","content":"In the world of Javascript, there are plenty of frameworks and libraries for building web applications. The most popular frontend technology is React and on the backend side - Express, Koa, or Nest.js. When building a full-stack app, it’s super important to plan the architecture, directory structure, and the way the data flow through a code. In this article, I’ll depict my solution to the problem of communication using the traditional REST API. \n\nAs an example, I would like to show different parts of my quiz application which I’ve been creating for the last months.  Click to go the project [here!](https://github.com/krzysztof01-sz/squizer-app-frontend)\n\n#### Dashboard component\n\nIn a dashboard component, we have a list of quizzes created by users. In order to get them from our database (MongoDB), we have to make a request to our API. That’s where the communication starts. \n\nGo here => /src/pages/Dashboard/index.js \n\n```\nconst Dashboard = () => {\n  const { data: quizzes, loading, error } = useFetching(getQuizzes);\n\n  if (loading) return <Loader />;\n  if (error) return <ErrorPage msg={error} />;\n\n  return (\n    <Layout>\n...\n```\n\n#### Frontend API\n\nIn line 2, I’m calling a custom hook (useFetching) with a getQuizzes argument. This argument is the reference to a function from the /src/api.index.js file. So let’s see how this function looks like and then, I’ll explain to you what happens in the useFetching hook. \n\n```\nexport const getQuizzes = async () => {\n  const { data } = await instance.get('/api/quizzes').catch(({ response }) => response);\n  return data;\n};\n```\n\nThis is a simple asynchronous function that sends a request to /api/quizzes using the axios package. I’m also using the catch method to gather potential errors. All the returned information is in a data property so I grab it using ES6 destructuring. \n\n#### Custom useFetching hook\n\nGo here => /src/hooks/useFetching.js \n\n\n```\nexport const useFetching = (method, ...methodArgs) => {\n  const [loading, setLoading] = useState(true);\n  const [error, setError] = useState(null);\n  const [data, setData] = useState(undefined);\n\n  useEffect(() => {\n    const cancelToken = axios.CancelToken;\n    const source = cancelToken.source();\n\n    (async () => {\n      const { type, data, msg } = await method([...methodArgs]);\n\n      if (type === responseTypes.success) {\n        setData(data);\n      } else {\n        setError(msg);\n      }\n\n      setLoading(false);\n    })();\n\n    return () => source.cancel();\n  }, []);\n\n  return { data, loading, error };\n};\n```\n\nThis function excepts the method to call and the array of the method arguments (if they exist). Below I declare state (loading, error, and data). In line 10, I’m calling the passed method with the potential arguments using the spread operator and then, destructuring the type of the response, data, and an error message (here it’s a msg value). After that, if the request finished successfully, I set the data, the error, and finally set the loading variable to false in order to inform that the request had been finished and a loader component can disappear. In the end, I return the object with all the necessary data. Don’t remember to close all subscriptions and asynchronous tasks in a cleanup function (here I’m using axios.CancelToken). Now, back to the first code snippet and look once again.\n\n\n```\n  const { data: quizzes, loading, error } = useFetching(getQuizzes);\n```\n\nHere, I’m destructuring the object returned from the hook and now, I can use that data to visualize the result: \n\n```\n  if (loading) return <Loader />;\n  if (error) return <ErrorPage msg={error} />;\n```\n\nAnd finally, list through the quizzes array. \n\n#### Express.js Backend\n\nNow, let’s head over to the backend to show how the request is processed there. \n\n[Backend here](https://github.com/krzysztof01-sz/squizer-app-backend/ )\n\nGo to => /routes/api.js \n\n```\nrouter.get(\"/quizzes\", verify, quizzesController.getQuizzes);\n```\n\nIn this line,  I created a GET /quizzes route that handles the request. This request is now forwarding to the dedicated quizzesController. Let’s take a look there. \n\n#### Controller\n\nThe role of the controller is to: \n\n<ul>\n<li>Obtain the request</li>\n<li>Call an appropriate service (if needed)</li>\n<li>Return a data or an error</li>\n</ul>\n\nAnd that’s what happens in a /controllers/quizzes.js file\n\n```\nmodule.exports.quizzesController = {\n  getQuizzes: async (req, res) => {\n    if (req.user) {\n      const { type, data, msg } = await QuizzesService.getQuizzes();\n\n      if (type === responseTypes.success) {\n        res.status(200).json({ type, data });\n      } else {\n        res.status(401).json({ type, msg });\n      }\n    }\n  },\n...\n```\n\nHere we have the getQuizzes method that meets the aforementioned requirements: \n<ul>\n<li>Obtain the request (line 2)</li>\n<li>Call an appropriate service (line 4)</li>\n<li>Return the data or error in according to thr returned type value (lines 6-</li>\n</ul>\nThe first and the third step is quite simple but the most interesting thing is in line 4. Here, I’m calling the quizzes service. \n\n#### Service\n\nThe role of the service is to handle more complex tasks, for instance, making database queries and preparing the data to pass to our controller. \n\n```\nclass QuizzesService {\n  async getQuizzes() {\n    try {\n      const quizzes = await Quiz.find({}).sort({ creationDate: -1 });\n\n      if (quizzes.length > 0) {\n        return {\n          type: responseTypes.success,\n          data: quizzes,\n        };\n      } else throw messages.QUIZZES_NOT_FOUND;\n    } catch (e) {\n      return makeResponse(e, responseTypes.error);\n    }\n  }\n...\n```\n\nIn the last step, I’m doing the query to MongoDB. I’m getting all quizzes, sorting them by the publish date. If the quizzes exist, I return them but if not, I catch an error and send them back. \n\nI recommend you to use try catch syntax to make the code more readable and easy to debug. \n\nVoila! The whole communication ends right here. Now, the data returned from this service are coming back to the controller, then to the frontend side (/src/api/index.js), next to the useFetching hook, and in the end to the appropriate React component (Dashboard) from which we’ve been started our long but cool trip! 😎 \n\nTo sum up, the communication step by step looks like this: \n\nReact component -> useFetching hook -> API method -> backend route -> controller -> service (we have the data) -> controller -> API method -> useFetching hook -> React component (we use the data). \n","date":"2021-06-01","minutesToRead":6,"slug":"how-to-cope-with-frontend-backend-communication-using-rest-api","categories":[{"name":"backend"},{"name":"frontend"}]}},"pageContext":{"slug":"how-to-cope-with-frontend-backend-communication-using-rest-api"}},"staticQueryHashes":["3114346481"]}